package com.ai.service.made.impl;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.ai.common.constant.*;
import com.ai.common.CommonResponse;


import com.ai.entity.alarm.*;
import com.ai.entity.function.FunctionPO;
import com.ai.entity.made.RegionBase;
import com.ai.entity.made.camera.CameraPO;
import com.ai.entity.network.IdentifySysToL1Message;
import com.ai.mapper.alarm.RecordAlarmMapper;
import com.ai.model.made.FaceDefectStats;
import com.ai.model.made.RegionalViolationDto;
import com.ai.model.made.TopFiveViolationsDto;
import com.ai.model.param.AlgorithmAlarmParam;
import com.ai.model.param.CGAlarmAdditionalParameter;
import com.ai.model.param.CGDefectParam;
import com.ai.model.vo.ActualRecordVo;
import com.ai.model.vo.CGFaceDefectVo;
import com.ai.model.vo.CGTXDefectInfoVo;
import com.ai.networking.websocket.service.WebSocket;
import com.ai.networking.websocket.service.entity.WSMessage;
import com.ai.service.made.*;
import com.ai.util.GetCameraPlaybackUrlUtil;
import com.ai.util.SecurityUtils;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static com.ai.common.constant.RecordAlarmConstant.TOWER_DEFECT_DETECTION;
import static com.ai.networking.netty.client.BootNettyClientChannelCache.clientSendMessage;

/**
 * <p>
 * 服务实现类
 *
 * </p>
 *
 * @author Mr.Chen
 * @since 2020-06-19
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class RecordAlarmServiceImpl extends ServiceImpl<RecordAlarmMapper, RecordAlarmPO> implements RecordAlarmService {


    @Resource
    IRegionManageService iRegionManageService;

    @Resource
    IRegionBaseService iRegionBaseService;

    @Resource
    RecordAlarmMapper recordAlarmMapper;
    @Resource
    CameraService cameraService;
    @Resource
    FunctionService functionService;

    @Resource
    L2SignalService l2SignalService;

    @Autowired
    private ServerService serverService;


//    @Resource
//    private MsgService msgService;

    @Autowired
    private AlarmAdditionalParameterService alarmAdditionalParameterService;

    @Autowired
    private DefectParamService defectParamService;


    private static volatile AtomicInteger FREQUENCY_A3_NUM = new AtomicInteger(0);


    /**
     * 算法提交识别警告
     *
     * @param alarmBOList
     * @return
     */
    @Override

    public CommonResponse addAlarm(List<AlgorithmAlarmBO> alarmBOList) {
        for (AlgorithmAlarmBO algorithmAlarmBO : alarmBOList) {




            if (StringUtils.isEmpty(algorithmAlarmBO.getSnapPhoto())) {
                return CommonResponse.error("没有抓拍图片");
            }

            if (StringUtils.isEmpty(algorithmAlarmBO.getFunctionType())) {
                return CommonResponse.error("没有警报类型");
            }

//            //统计各个缺陷图片的索引位置
//            List<CGAlarmAdditionalParameter.SideDefectContent> defectContentList = algorithmAlarmBO.getSideDefectContents();
//            //用于汇总各缺陷面，不同缺陷类型的图片索引信息
//            HashMap<String, FaceDefectStats> defectStatsHashMap = new HashMap<>(16);
//            for (CGAlarmAdditionalParameter.SideDefectContent sideDefectContent : defectContentList) {
//                String faceType = sideDefectContent.getFaceType();
//                //各个缺陷所在图片位置索引及缺陷类型
//                List<CGDefectParam> cgDefectParamList = sideDefectContent.getCgDefectParam();
//                //如果 faceType 已存在，返回已存在的 FaceDefectStats, 如果不存在，则创建新的实例返回，并放入Map中
//                FaceDefectStats faceDefectStats = defectStatsHashMap.computeIfAbsent(faceType, k -> new FaceDefectStats(faceType));
//
//                //开始统计各个缺陷信息
//                for (CGDefectParam cgDefectParam : cgDefectParamList) {
//                    //缺陷类型
//                    String defectType = cgDefectParam.getDefectType();
//                    //具体缺陷内容
//                    List<CGDefectParam.DefectContent> contentList = cgDefectParam.getDefectContent();
//
//                    for (CGDefectParam.DefectContent defectContent : contentList) {
//                        Integer defectIndex = defectContent.getDefectIndex();
//                        faceDefectStats.addDefectTypeIndex(Integer.valueOf(defectType),defectIndex);
//                    }
//                }
//            }


            RecordAlarmPO alarmPO = new RecordAlarmPO();
            //算法提交的图片为路径 给的是nginx代理之后的路径： 127.0.0.1:81/images/日期/钢卷号/ResultImages 。。。。。
            //注 ： RawImages 【原图】   Renders 【渲染图】---打框打好的  Thumbnails 【缩略图】
            String webPhotoPath = algorithmAlarmBO.getSnapPhoto();
            String webVideoPath = algorithmAlarmBO.getSnapVideo();


//            int sixthSlashIndex = webPhotoPath.indexOf("/", webPhotoPath.indexOf("/", webPhotoPath.indexOf("/", webPhotoPath.indexOf("/", webPhotoPath.indexOf("/") + 1) + 1) + 1) + 1) + 1;
//            String result = webPhotoPath.substring(sixthSlashIndex);

            CameraPO cameraPO = new CameraPO();
            if (algorithmAlarmBO.getFunctionType().equals(TOWER_DEFECT_DETECTION)) {
                //塔形
                String cameraCode = algorithmAlarmBO.getCameraCode();
                //根据设下摄像头code查询相关的摄像头信息
                cameraPO = cameraService.getByCode(cameraCode);
                if (cameraPO == null) {
                    return CommonResponse.error("摄像头不存在");
                }
//                alarmPO.setSnapPhoto("127.0.0.1:80/file/" + result + "/" + "Renders" + "/" + cameraCode + ".png");
                alarmPO.setSnapPhoto(webPhotoPath+ "/" + "Renders" + "/" + cameraCode + ".png");
            } else if (algorithmAlarmBO.getFunctionType().equals(RecordAlarmConstant.END_DEFECT_DETECTION)) {

                List<CameraPO> list = cameraService.list(new QueryWrapper<>());
                cameraPO = list.get(0);
                if (cameraPO == null) {
                    return CommonResponse.error("摄像头不存在");
                }
                //端面的交由前端按照规则去拼接路径，展示缩略图和渲染图
                alarmPO.setSnapPhoto(webPhotoPath);
            }

            //格式
            SimpleDateFormat sformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            Date date = new Date();
            try {
                if (!StringUtils.isEmpty(algorithmAlarmBO.getCreateTime())) {
                    date = sformat.parse(algorithmAlarmBO.getCreateTime());
                }
            } catch (ParseException e) {
                log.error("===========================  告警日期格式化错误  ===========================");
                log.error(e.getMessage());
            }


            Integer type = Integer.parseInt(algorithmAlarmBO.getFunctionType());

            //保存违规对象
            //视频路径
            alarmPO.setSnapVideo(algorithmAlarmBO.getSnapVideo());
            alarmPO.setCameraId(cameraPO.getId());
            alarmPO.setCameraCode(cameraPO.getCode());
            //代钢号
            alarmPO.setStripNo(algorithmAlarmBO.getStripNo());
            alarmPO.setFunctionType(type);
            //塔型宽度
            alarmPO.setWidth(algorithmAlarmBO.getWidth());
            alarmPO.setSnapVideo(webVideoPath);
            alarmPO.setSubgroup(type);
            alarmPO.setCreateTime(date);
            alarmPO.setIsState(algorithmAlarmBO.getState());
            alarmPO.setUpdateTime(date);

            save(alarmPO);
            //得到刚存入报警信息的Id
            Integer recordId = alarmPO.getId();

            if (recordId == null) {
                return CommonResponse.error("插入报警信息表错误");
            }
            //创建告警参数对象
            AlarmAdditionalParameter alarmAdditionalParameter = new AlarmAdditionalParameter();
            alarmAdditionalParameter.setRecordAlarmId(recordId);
            alarmAdditionalParameter.setTelegramReceivedContent(algorithmAlarmBO.getTelegramReceivedContent());
            alarmAdditionalParameter.setTelegramSendDate(algorithmAlarmBO.getTelegramSendDate());
            alarmAdditionalParameter.setSteelThickness(algorithmAlarmBO.getSteelThickness());
            alarmAdditionalParameter.setSteelDiameter(algorithmAlarmBO.getSteelDiameter());
            alarmAdditionalParameter.setSteelWidth(algorithmAlarmBO.getSteelWidth());
            alarmAdditionalParameter.setStripNo(algorithmAlarmBO.getStripNo());

            //各面缺陷信息
            List<CGAlarmAdditionalParameter.SideDefectContent> sideDefectContents = algorithmAlarmBO.getSideDefectContents();
            //存到参数信息表中
            alarmAdditionalParameterService.insert(alarmAdditionalParameter);

            Integer alarmAdditionalParameterId = alarmAdditionalParameter.getId();
            if (alarmAdditionalParameterId == null) {
                return CommonResponse.error("插入告警参数表错误");
            }

            for (CGAlarmAdditionalParameter.SideDefectContent sideDefectContent : sideDefectContents) {

                List<CGDefectParam> cgDefectParam = sideDefectContent.getCgDefectParam();

                for (CGDefectParam param : cgDefectParam) {
                    List<CGDefectParam.DefectContent> defectContent = param.getDefectContent();
                    if (CollectionUtils.isEmpty(defectContent)){
                        continue;
                    }
                    for (CGDefectParam.DefectContent content : defectContent) {
                        DefectParam defectParam = new DefectParam();
                        defectParam.setAlarmAdditionId(alarmAdditionalParameterId);
                        defectParam.setDefectType(param.getDefectType());
                        defectParam.setCreateTime(new Date());
                        defectParam.setUpdateTime(new Date());
                        // 端面检测分为a面，b面，会有入参传递过来进行区分
                        if ("a".equals(sideDefectContent.getFaceType()) || "b".equals(sideDefectContent.getFaceType())) {


                            if ("a".equals(sideDefectContent.getFaceType())) {
                                defectParam.setFaceType(RecordAlarmConstant.SIDE_A);
                            } else {
                                defectParam.setFaceType(RecordAlarmConstant.SIDE_B);
                            }


                            if (algorithmAlarmBO.getFunctionType().equals(RecordAlarmConstant.END_DEFECT_DETECTION)) {
                                //端面缺陷检测
                                defectParam.setX(content.getX());
                                defectParam.setY(content.getY());
                                defectParam.setDefectIndex(content.getDefectIndex());
                            } else if (algorithmAlarmBO.getFunctionType().equals(TOWER_DEFECT_DETECTION)) {
                                //塔形检测
                                defectParam.setX(0.0);
                                defectParam.setY(0.0);
                                defectParam.setDefectIndex(-1);
                            } else {
                                return CommonResponse.error("检测类型不存在,插入失败");
                            }
                            defectParamService.insert(defectParam);
                            if (defectParam.getId() == null) {
                                return CommonResponse.error("插入缺陷详细信息表失败");
                            }
                        } else {
                            return CommonResponse.error("面类型不存在,插入失败");
                        }
                    }
                }
            }
            sendWebSocket(type);
            algorithmAlarmBO.setSnapPhoto(webPhotoPath);
            algorithmAlarmBO.setSnapVideo(webVideoPath);
        }
        return CommonResponse.ok("警告发送成功");
    }


    @Override
//    @Transactional
    public CommonResponse addWarningRecord(AlgorithmAlarmParam algorithmAlarmParams) {

        //查询警告的功能类型
        List<String> alarmParamsTypes = algorithmAlarmParams.getTypes();
        ArrayList<AlgorithmAlarmBO> alarmBOArrayList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(alarmParamsTypes)) {
            for (String type : alarmParamsTypes) {

                if (type.equals(TOWER_DEFECT_DETECTION)) {
                    for (String cameraCode : algorithmAlarmParams.getCameraCode()) {
                        AlgorithmAlarmBO algorithmAlarmBO = new AlgorithmAlarmBO();
                        BeanUtils.copyProperties(algorithmAlarmParams, algorithmAlarmBO);
                        algorithmAlarmBO.setFunctionType(type);
                        algorithmAlarmBO.setCameraCode(cameraCode);

                        //塔型宽度
                        String w = "";
                        if (cameraCode.equals("TX0")){
                            for (CGAlarmAdditionalParameter.SideDefectContent sideDefectContent : algorithmAlarmParams.getSideDefectContents()) {
                                if (sideDefectContent.getFaceType().equals("a")){
                                     w = StrUtil.isEmpty(sideDefectContent.getCgDefectParam().get(0).getWidth()) ? "0" : sideDefectContent.getCgDefectParam().get(0).getWidth();
                                }
                            }
                        }else {
                            for (CGAlarmAdditionalParameter.SideDefectContent sideDefectContent : algorithmAlarmParams.getSideDefectContents()) {
                                if (sideDefectContent.getFaceType().equals("b")){
                                    w = StrUtil.isEmpty(sideDefectContent.getCgDefectParam().get(0).getWidth()) ? "0" : sideDefectContent.getCgDefectParam().get(0).getWidth();
                                }
                            }
                        }
                        algorithmAlarmBO.setWidth(w);
                        alarmBOArrayList.add(algorithmAlarmBO);
                    }
                } else if (type.equals(RecordAlarmConstant.END_DEFECT_DETECTION)) {
                    AlgorithmAlarmBO algorithmAlarmBO = new AlgorithmAlarmBO();
                    BeanUtils.copyProperties(algorithmAlarmParams, algorithmAlarmBO);
                    algorithmAlarmBO.setFunctionType(type);
                    alarmBOArrayList.add(algorithmAlarmBO);
                } else {
                    return CommonResponse.error("报警类型错误");
                }
            }
            return this.addAlarm(alarmBOArrayList);
        }
        return CommonResponse.error("未携带警告类型");
    }


    /**
     * 向plc发送消息
     *
     * @param signalRecord
     * @param algorithmAlarmBO
     */
    private void sendMsgToPlc(SignalRecord signalRecord, AlgorithmAlarmBO algorithmAlarmBO, String plcCode) {

        String nettyCode = signalRecord.getNettyCode();
        Integer telID = getTelIDByFunType(Integer.parseInt(algorithmAlarmBO.getFunctionType()), signalRecord.getSignalResource());

        IdentifySysToL1Message identifySysToL1Message = new IdentifySysToL1Message();
        identifySysToL1Message.setTelID(telID);//电文号
        identifySysToL1Message.setPlanNo(algorithmAlarmBO.getStripNo());//版批号
        identifySysToL1Message.setDoorNum(algorithmAlarmBO.getDoorNum());//炉门编号
        identifySysToL1Message.setResult(algorithmAlarmBO.getResult());// 1 正常 2 异常
//        identifySysToL1Message.setSpare();
        String jsonString = JSONObject.toJSONString(identifySysToL1Message);
        int length = jsonString.getBytes().length;

        //填充真实数据的字节长度
        identifySysToL1Message.setTelLen(length);

        String msgJSON = JSONObject.toJSONString(identifySysToL1Message);

        clientSendMessage(plcCode, msgJSON);

    }

    public static Integer getTelIDByFunType(Integer funType, String clientIp) {

        Integer telID = 0;

        if (funType.equals(FunctionTypeConstants.A3_TRANSFER_SLAB_DEVIATION)) {
            telID = AlgorithmConstant.A3_TRANSFER_MACHINE_AUTOMATIC_CONFIRMATION;
        } else if (funType.equals(FunctionTypeConstants.SUPERPOSE_STEEL_IDENTIFICATION)) {
            //一个信号开启了两个功能，  那么收到某一个功能的信号识别记录是否需要通知plc
            telID = AlgorithmConstant.TRACK_STACKING_STEEL;

        } else if (funType.equals(FunctionTypeConstants.RANGING_STEEL)) {
            telID = AlgorithmConstant.TRACK_STACKING_STEEL;

        } else if (funType.equals(FunctionTypeConstants.LOAD_STEEL_DEVIATION) && clientIp.equals(PlcConstants.PLC_2_IP)) {
            telID = AlgorithmConstant.STEEL_INSTALLATION_DEVIATION_30_4;

        } else if (funType.equals(FunctionTypeConstants.TAKE_STEEL_DEVIATION) && clientIp.equals(PlcConstants.PLC_2_IP)) {
            telID = AlgorithmConstant.STEEL_DRAWING_DEVIATION_30_4;

        } else if (funType.equals(FunctionTypeConstants.STOVE_STATUS) && clientIp.equals(PlcConstants.PLC_2_IP)) {
            telID = AlgorithmConstant.FURNACE_DOOR_STATUS_30_4;

        } else if (funType.equals(FunctionTypeConstants.LOAD_STEEL_DEVIATION) && clientIp.equals(PlcConstants.PLC_3_IP)) {
            telID = AlgorithmConstant.STEEL_INSTALLATION_DEVIATION_30_5;

        } else if (funType.equals(FunctionTypeConstants.TAKE_STEEL_DEVIATION) && clientIp.equals(PlcConstants.PLC_3_IP)) {
            telID = AlgorithmConstant.STEEL_DRAWING_DEVIATION_30_5;

        } else if (funType.equals(FunctionTypeConstants.STOVE_STATUS) && clientIp.equals(PlcConstants.PLC_3_IP)) {
            telID = AlgorithmConstant.FURNACE_DOOR_STATUS_30_5;

        }
        return telID;
    }


    private void sendWebSocket(int type) {
        WSMessage wsMessage = new WSMessage();
        wsMessage.setContent("UPDATE");

        if (CommonArgs.WS_RECORD_MAP.containsKey(type)
                && CommonArgs.WS_RECORD_MAP.get(type) != null
                && CommonArgs.WS_RECORD_MAP.get(type).size() > 0) {
            CopyOnWriteArraySet<WebSocket> webSockets = CommonArgs.WS_RECORD_MAP.get(type);
            for (WebSocket ws : webSockets) {
                ws.sendMessage(wsMessage);
            }
        }
    }

    private void sendHttp(RecordAlarmPO alarmPO) {


    }


    /**
     * 分页查询
     *
     * @param page
     * @return
     */
    @Override
    public CommonResponse selectByPage(RecordAlarmPage page) {
        IPage<RecordAlarmVO> voIPage = new BasePage<>();

        //获取当前区域管理的摄像头
        HashMap<String, String> cameraRegionMap = SecurityUtils.getRegionManageCamerasCode(iRegionBaseService, iRegionManageService);
        if (CollectionUtils.isEmpty(cameraRegionMap)) {
            //当前区域没有管理任何摄像头
            return CommonResponse.ok(voIPage);
        }
        //获取所有摄像头code
        if (StringUtils.isEmpty(page.getRegionBaseId())) {
            ArrayList<String> cameraCodes = new ArrayList<>(cameraRegionMap.keySet());
            page.setCameraCodes(cameraCodes);
        } else {
            CommonResponse bindList = iRegionManageService.getBindList(page.getRegionBaseId());
            ArrayList<String> bindListData = (ArrayList<String>) bindList.getData();
            page.setCameraCodes(bindListData);
        }
        log.info("===========================  cameraCodes  ===========================,{}", page.getCameraCodes());


        QueryWrapper<RecordAlarmVO> queryWrapper = new QueryWrapper<>();
        // 增强输入验证
        if (page.getFunctionType() == null) {
            return CommonResponse.error("功能类型不能为空");
        }
        queryWrapper = page.getQuery(queryWrapper);
//        queryWrapper.eq("function_type","1147");
        if (page.getFunctionType() != null && page.getFunctionType().equals(RecordAlarmConstant.END_DEFECT_DETECTION)) {
            //端面检测
            queryWrapper.eq("ra.function_type", RecordAlarmConstant.END_DEFECT_DETECTION);
            voIPage = recordAlarmMapper.selectRecodAlarm(page, queryWrapper, RecordAlarmConstant.END_DEFECT_DETECTION);

        }
        else if (page.getFunctionType() != null && page.getFunctionType().equals(TOWER_DEFECT_DETECTION)) {
            //塔形检测
            queryWrapper.eq("ra.function_type", TOWER_DEFECT_DETECTION);
            voIPage = recordAlarmMapper.selectRecodAlarmTower(page, queryWrapper);
            List<RecordAlarmVO> records = voIPage.getRecords();
            for (RecordAlarmVO record : records) {
                if (record.getIsError() == 9) {
                    break;
                }
                String name = functionService.getNameByCode(record.getFunctionType());
                CameraPO cameraPO = cameraService.getById(record.getCameraId());
                String regionCode = cameraRegionMap.get(cameraPO.getCode());
                RegionBase regionBaseByCode = iRegionBaseService.getRegionBaseByCode(regionCode);
                //区域名
                record.setRegionName(regionBaseByCode.getRegionName());
                record.setFunctionNickname(name);
                record.setCameraNickname(cameraPO == null ? "" : cameraPO.getNickname());
            }

        } else {
            return CommonResponse.error("缺陷类型错误");
        }
        List<RecordAlarmVO> records = voIPage.getRecords();
        for (RecordAlarmVO record : records) {
            RecordAlarmPO recordAlarmPO = recordAlarmMapper.selectById(record.getId());
            if (recordAlarmPO != null) {
                record.setSnapPhoto(recordAlarmPO.getSnapPhoto());
            }
        }

        return CommonResponse.ok(voIPage);
    }

    //集合去重
    public static List<Integer> removeDuplicate(List<Integer> list) {
        HashSet<Integer> h = new HashSet(list);
        list.clear();
        list.addAll(h);
        return list;
    }


    /**
     * 根据报警id查询相关缺陷信息
     *
     * @param recordAlarmId 报警信息表id
     * @return
     */
    @Override
    public CommonResponse selectDefectParamById(Integer recordAlarmId) {
        AlarmAdditionalParameter alarmAdditionalParameter = alarmAdditionalParameterService.selectByRecordAlarmId(recordAlarmId);
        if (alarmAdditionalParameter == null) {
            return CommonResponse.error("报警参数信息不存在");
        }
        Integer id = alarmAdditionalParameter.getId();
        List<DefectParam> list = defectParamService.selectByAlarmAdditionId(id);
        HashMap<String,List<Integer>> faceDefectIndexMap = defectParamService.getDefectIndexMap(id);

        if (list == null) {
            return CommonResponse.error("报警详细信息不存在");
        }
        RecordAlarmPO byId = this.getById(recordAlarmId);
        RecordAlarmVO recordAlarmVO = new RecordAlarmVO();
        recordAlarmVO.setStripNo(alarmAdditionalParameter.getStripNo());
        recordAlarmVO.setSteelWidth(alarmAdditionalParameter.getSteelWidth());
        recordAlarmVO.setSteelDiameter(alarmAdditionalParameter.getSteelDiameter());
        recordAlarmVO.setSteelThickness(alarmAdditionalParameter.getSteelThickness());
        recordAlarmVO.setSnapPhoto(byId.getSnapPhoto());
        Map<String, List<Integer>> defectContentMap = new HashMap<>();
        for (DefectParam defectParam : list) {
            String faceType = defectParam.getFaceType();
            String key = faceType;
            //获取指定 key 对应对 value，如果找不到 key ，则返回设置的默认值。
            List<Integer> defectContentList = defectContentMap.getOrDefault(key, new ArrayList<>());
            defectContentList.add(defectParam.getDefectIndex());

        }

        RecordAlarmVO.SideDefectContent sideDefectContentA = new RecordAlarmVO.SideDefectContent();
        sideDefectContentA.setFaceType(RecordAlarmConstant.SIDE_A);
        List<Integer> cgDefectParamsA = RecordAlarmServiceImpl.removeDuplicate(getCGDefectParams(defectContentMap, RecordAlarmConstant.SIDE_A));
        sideDefectContentA.setIndex(cgDefectParamsA);

        RecordAlarmVO.SideDefectContent sideDefectContentB = new RecordAlarmVO.SideDefectContent();
        sideDefectContentB.setFaceType(RecordAlarmConstant.SIDE_B);
        List<Integer> cgDefectParamsB = RecordAlarmServiceImpl.removeDuplicate(getCGDefectParams(defectContentMap, RecordAlarmConstant.SIDE_B));
        sideDefectContentB.setIndex(cgDefectParamsB);

        //Arrays.asList将数组转成集合
        recordAlarmVO.setSideDefectContents(Arrays.asList(sideDefectContentA, sideDefectContentB));
        recordAlarmVO.setFaceDefectIndexMap(faceDefectIndexMap);
        return CommonResponse.ok(recordAlarmVO);
    }

    @Override
    public CommonResponse getUpToDateAlarm() {

        LambdaQueryWrapper<RecordAlarmPO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(RecordAlarmPO::getFunctionType, RecordAlarmConstant.END_DEFECT_DETECTION);
        lambdaQueryWrapper.orderByDesc(RecordAlarmPO::getCreateTime)
                .last("limit 5");
        List<RecordAlarmPO> recordAlarmPOList = recordAlarmMapper.selectList(lambdaQueryWrapper);

        CGFaceDefectVo cgFaceDefectVo = new CGFaceDefectVo();

        for (RecordAlarmPO recordAlarmPO : recordAlarmPOList) {

            Integer alarmPOId = recordAlarmPO.getId();
            AlarmAdditionalParameter alarmAdditionalParameter = alarmAdditionalParameterService.selectByRecordAlarmId(alarmPOId);
            if (alarmAdditionalParameter == null) {
                 log.error("{}报警参数信息不存在",recordAlarmPO.getStripNo());
                 break;
            }

            HashMap<String, List<String>> defectTypeMap = defectParamService.getDefectTypeMap(alarmAdditionalParameter.getId());

            cgFaceDefectVo.setStripNo(alarmAdditionalParameter.getStripNo());
            cgFaceDefectVo.setCrateTime(DateUtil.formatDateTime(recordAlarmPO.getCreateTime()));
            cgFaceDefectVo.setSnapPhoto(recordAlarmPO.getSnapPhoto());
            cgFaceDefectVo.setFaceDefectMap(defectTypeMap);
            break;
        }

        return CommonResponse.ok(cgFaceDefectVo);
    }

    @Override
    public CommonResponse getUpToDateTXAlarm() {

        List<RecordAlarmPO> recordAlarmPOList = recordAlarmMapper.getUpToDateTXAlarm();

        CGTXDefectInfoVo cgtxDefectInfoVo = new CGTXDefectInfoVo() ;

        List<CameraPO> cameraPOList = cameraService.list(new QueryWrapper<CameraPO>().in("code", "TX0", "TX1"));
        Map<Integer, String> cameraCodeRelation = cameraPOList.stream().collect(Collectors.toMap(CameraPO::getId, CameraPO::getCode));
        if (CollectionUtils.isEmpty(recordAlarmPOList)){
            return CommonResponse.ok();
        }else {
            for (RecordAlarmPO recordAlarmPO : recordAlarmPOList) {
                CGTXDefectInfoVo cgtxDefectInfo  = new CGTXDefectInfoVo();
                cgtxDefectInfo.setStripNo(recordAlarmPO.getStripNo());
                cgtxDefectInfo.setCrateTime(DateUtil.formatDateTime(recordAlarmPO.getCreateTime()));

                List<RecordAlarmPO> txRecordAlarmList = recordAlarmMapper.selectList(new QueryWrapper<RecordAlarmPO>()
                        .eq("strip_no", recordAlarmPO.getStripNo()).eq("function_type",TOWER_DEFECT_DETECTION).orderByDesc("create_time").last("limit 2"));
                if (CollectionUtils.isEmpty(txRecordAlarmList)){
                    continue;
                } else if (!CollectionUtils.isEmpty(txRecordAlarmList) && txRecordAlarmList.size() == 1) {
                    //仅有一个面
                    RecordAlarmPO alarmPO = txRecordAlarmList.get(0);
                    if (constructTxInfo(cameraCodeRelation, cgtxDefectInfo, alarmPO)) continue;
                    String cameraCode = cameraCodeRelation.get(alarmPO.getCameraId());
                    //手动填充另一个面
                    fillTxInfo(cameraCode,cgtxDefectInfo);
                    cgtxDefectInfoVo = cgtxDefectInfo;
                    break;
                }else {
                    //存在两个面的信息

                    //信息面1
                    RecordAlarmPO alarmPO1 = txRecordAlarmList.get(0);
                    if (constructTxInfo(cameraCodeRelation, cgtxDefectInfo, alarmPO1)) continue;
                    //信息面2
                    RecordAlarmPO alarmPO2 = txRecordAlarmList.get(1);
                    if (constructTxInfo(cameraCodeRelation, cgtxDefectInfo, alarmPO2)) continue;

                    cgtxDefectInfoVo = cgtxDefectInfo;
                    break;
                }
            }
        }

        if(CollectionUtils.isEmpty(cgtxDefectInfoVo.getTxInfoList()) || cgtxDefectInfoVo.getTxInfoList().size()<2){
            cgtxDefectInfoVo.setStripNo(recordAlarmPOList.get(0).getStripNo());
            cgtxDefectInfoVo.setCrateTime(DateUtil.formatDateTime(recordAlarmPOList.get(0).getCreateTime()));
            fillTxInfo("TX0",cgtxDefectInfoVo);
            fillTxInfo("TX1",cgtxDefectInfoVo);
        }

        cgtxDefectInfoVo.sortTxInfoListByFaceType();

        return CommonResponse.ok(cgtxDefectInfoVo);
    }

    private static void fillTxInfo(String cameraCode,CGTXDefectInfoVo cgtxDefectInfo){

        CGTXDefectInfoVo.TXInfo txInfo = new CGTXDefectInfoVo.TXInfo();
        txInfo.setIsState(String.valueOf(1));
        txInfo.setFaceType("TX0".equals(cameraCode)?"TX1":"TX0");
        cgtxDefectInfo.addTxInfoList(txInfo);


    }

    /**
     * 组建首页塔型详细界面信息
     * @param cameraCodeRelation tx1，tx2 对应的摄像头信息
     * @param cgtxDefectInfo vo
     * @param alarmPO 告警信息
     * @return 如果摄像头id对不上，则取第二条钢卷号组建信息
     */
    private static boolean constructTxInfo(Map<Integer, String> cameraCodeRelation, CGTXDefectInfoVo cgtxDefectInfo, RecordAlarmPO alarmPO) {
        String cameraCode = cameraCodeRelation.get(alarmPO.getCameraId());
        if (null == cameraCode){
            return true;
        }else {
            CGTXDefectInfoVo.TXInfo txInfo = new CGTXDefectInfoVo.TXInfo();
            txInfo.setIsState(String.valueOf(alarmPO.getIsState()));
            txInfo.setFaceType(cameraCode);
            txInfo.setSnapPhoto(alarmPO.getSnapPhoto());
            cgtxDefectInfo.addTxInfoList(txInfo);
        }
        return false;
    }

    private List<Integer> getCGDefectParams(Map<String, List<Integer>> defectContentMap, String faceType) {
        String key = faceType;
        List<Integer> defectContentList = defectContentMap.getOrDefault(key, new ArrayList<>());
        return defectContentList;
    }


    /**
     * 是否误报
     *
     * @param recordAlarmBO
     * @return
     */
    @Override
    public CommonResponse signError(RecordAlarmBO recordAlarmBO) {
        RecordAlarmBO alarmBO = new RecordAlarmBO();
        alarmBO.setId(recordAlarmBO.getId());
        alarmBO.setIsError(recordAlarmBO.getIsError());
        alarmBO.setReviewComments(recordAlarmBO.getReviewComments());
        RecordAlarmPO recordAlarmPO = RecordAlarmBO.convertBOToPO(alarmBO);
        if (updateById(recordAlarmPO)) {
            return CommonResponse.ok("标记成功");
        }
        return CommonResponse.error("标记失败");
    }

    @Override
    public List<RecordAlarmPO> getRecordByCameraCodeAndFunType(ArrayList<String> cameraCode, String funType) {

        List<RecordAlarmPO> recordAlarmPOList = recordAlarmMapper.getRecordByCameraCodeAndFunType(cameraCode, funType);

        return recordAlarmPOList;
    }

    @Override
    public List<TopFiveViolationsDto> topFiveViolations() {

        List<TopFiveViolationsDto> topFiveViolationsDtos = this.baseMapper.topFiveViolations();

        return topFiveViolationsDtos;
    }

    @Override
    public List<RegionalViolationDto> regionalViolation() {

        List<RegionalViolationDto> regionalViolationDtoList = this.baseMapper.regionalViolation();

        return regionalViolationDtoList;
    }

    @Override
    public CommonResponse latestRecord() {
        // 获取当前日期
        LocalDate today = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String date = today.format(formatter);

        QueryWrapper<RecordAlarmPO> queryWrapper = new QueryWrapper<>();
        //只获取当天的最新十条
        queryWrapper.ge("create_time", date);
        queryWrapper.orderByDesc("create_time");
        queryWrapper.last("limit 10");
        List<RecordAlarmPO> latestRecordList = this.list(queryWrapper);

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// DATE格式化
        ArrayList<ActualRecordVo> recordVoArrayList = new ArrayList<>();

        if (!CollectionUtils.isEmpty(latestRecordList)) {
            for (RecordAlarmPO recordAlarmPO : latestRecordList) {
                //组装实时违规记录字段
                ActualRecordVo actualRecordVo = new ActualRecordVo();

                CameraPO cameraPO = cameraService.getById(recordAlarmPO.getCameraId());

                if (null != cameraPO) {
                    actualRecordVo.setCameraName(cameraPO.getNickname());
                    actualRecordVo.setCameraCode(cameraPO.getCode());
                }
                FunctionPO functionPO = functionService.getFunByType(recordAlarmPO.getFunctionType());
                if (null != functionPO) {
                    actualRecordVo.setFunName(functionPO.getNickname());
                }
                RegionBase regionBase = iRegionBaseService.getRegionByCameraId(cameraPO.getId());
                if (null != regionBase) {
                    actualRecordVo.setRegionName(regionBase.getRegionName());
                }
                actualRecordVo.setViolationTime(simpleDateFormat.format(recordAlarmPO.getCreateTime()));

                recordVoArrayList.add(actualRecordVo);
            }
        }

        return CommonResponse.ok(recordVoArrayList);
    }

    @Override
    public CommonResponse getCameraPlaybackUrl(String recordId) {

        /**
         * 根据告警记录id，查找对应的摄像头
         */
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        RecordAlarmPO recordAlarmPO = this.getById(recordId);

        String serverIp = this.getServerIpByRecord(recordId);

        String previewUrl = GetCameraPlaybackUrlUtil.getCameraPlaybackUrl(recordAlarmPO.getCameraCode(), simpleDateFormat.format(recordAlarmPO.getCreateTime()));
        HashMap<String, Object> res = new HashMap<>(16);
        res.put("url", previewUrl);
        res.put("serverIp", serverIp);
        return CommonResponse.ok(res);

    }


    /**
     * 获取服务器ip
     *
     * @param recordId
     * @return
     */
    private String getServerIpByRecord(String recordId) {

        return baseMapper.getServerIpByRecord(recordId);

    }


}
